package com.github.czyzby.lml.uedi.i18n; import java.lang.reflect.Member; import java.util.Locale; import com.badlogic.gdx.Gdx; import com.badlogic.gdx.assets.AssetManager; import com.badlogic.gdx.utils.Array; import com.badlogic.gdx.utils.I18NBundle; import com.badlogic.gdx.utils.ObjectMap; import com.badlogic.gdx.utils.ObjectMap.Entry; import com.github.czyzby.kiwi.util.common.Exceptions; import com.github.czyzby.kiwi.util.common.Strings; import com.github.czyzby.kiwi.util.gdx.collection.GdxMaps; import com.github.czyzby.kiwi.util.gdx.collection.lazy.LazyObjectMap; import com.github.czyzby.lml.parser.LmlParser; import com.github.czyzby.lml.uedi.assets.Loaded; import com.github.czyzby.lml.uedi.assets.impl.AbstractAssetProvider; import com.github.czyzby.lml.uedi.assets.impl.InjectingAssetManager; import com.github.czyzby.lml.uedi.i18n.impl.BundleInjection; import com.github.czyzby.lml.uedi.i18n.impl.EagerI18NBundleLoader.EagerI18NBundleParameter; import com.github.czyzby.uedi.reflection.impl.FieldMember; /** Provides {@link I18NBundle} instances. Automatically adds bundles to {@link LmlParser}. * * @author MJ */ public class I18NBundleProvider extends AbstractAssetProvider<I18NBundle> { /** This is the initial default bundle name, which will be set as the main bundle in {@link LmlParser}. */ public static final String DEFAULT_BUNDLE = "nls"; public static final String[] EXTENSIONS = new String[] { "" }; private final ObjectMap<String, I18NBundle> bundles = GdxMaps.newObjectMap(); private final ObjectMap<String, Array<BundleInjection>> bundlesData = LazyObjectMap.newMapOfArrays(); private LocalePreference localePreference; private LmlParser parser; private String encoding = "UTF-8"; private String defaultBundle = DEFAULT_BUNDLE; /** @param assetManager will be used to load the textures. */ public I18NBundleProvider(final InjectingAssetManager assetManager) { super(assetManager); } /** @param localePreference will be used to determine current {@link Locale}. */ public void setLocalePreference(final LocalePreference localePreference) { this.localePreference = localePreference; } /** @return preference used to determine current {@link Locale}. */ public LocalePreference getLocalePreference() { return localePreference; } /** @return default bundle name, which will be set as the main bundle in {@link LmlParser}. */ public String getDefaultBundle() { return defaultBundle; } /** @param defaultBundle default bundle name, which will be set as the main bundle in {@link LmlParser}. */ public void setDefaultBundle(final String defaultBundle) { this.defaultBundle = defaultBundle; } @Override public I18NBundle provide(final Object target, final Member member) { if (member == null) { throwUnknownPathException(); } final String id = member.getName(); if (id.isEmpty()) { throwUnknownPathException(); } final I18NBundle asset = getOrLoad(id); if (member instanceof FieldMember) { final BundleInjection injection = new BundleInjection(determinePath(id), ((FieldMember) member).getField(), target); if (target instanceof Loaded) { ((Loaded) target).onLoad(determinePath(id), I18NBundle.class, asset); } bundlesData.get(id).add(injection); } return asset; } @Override public Class<? extends I18NBundle> getType() { return I18NBundle.class; } @Override public I18NBundle getOrLoad(final String id) { if (bundles.containsKey(id)) { return bundles.get(id); } final String path = determinePath(id); final I18NBundle bundle = I18NBundle.createBundle(Gdx.files.internal(path), localePreference.getLocale(), encoding); bundles.put(id, bundle); final EagerI18NBundleParameter parameters = new EagerI18NBundleParameter(bundle); getAssetManager().load(path, I18NBundle.class, parameters); return bundle; } @Override protected String determinePath(final String id) { final ObjectMap<String, String> idsToPaths = getIdsToPaths(); String path = idsToPaths.get(id); if (path != null) { return path; } final StringBuilder builder = new StringBuilder(getFolder().length() + 1 + id.length()); builder.append(getFolder()).append('/').append(id); Strings.replace(builder, '_', '/'); path = builder.toString(); idsToPaths.put(id, path); return path; } /** @return encoding used to read {@link I18NBundle} files. Defaults to UTF-8. */ public String getEncoding() { return encoding; } /** @param encoding will be used to read {@link I18NBundle} files. */ public void setEncoding(final String encoding) { this.encoding = encoding; } @Override protected String getFileName(final String folder, final String id) { final StringBuilder builder = new StringBuilder(folder.length() + 1 + id.length()); builder.append(folder); builder.append('/'); builder.append(id); Strings.replace(builder, '_', '/'); return builder.toString(); // No extension, no dot required. } /** Should be called after bundles are loaded. * * @param parser will have the bundles attached in its parsing data. Will be updated on bundle reloads. */ public void fill(final LmlParser parser) { this.parser = parser; for (final Entry<String, I18NBundle> bundle : bundles) { parser.getData().addI18nBundle(bundle.key, bundle.value); if (defaultBundle.equals(bundle.key)) { parser.getData().setDefaultI18nBundle(bundle.value); } } } /** Reloads all managed {@link I18NBundle} instances according to the current state of {@link LocalePreference}. */ public void reloadBundles() { reloadBundles(localePreference.getLocale()); } /** @param locale will be used to reload all managed {@link I18NBundle} instances. */ public void reloadBundles(final Locale locale) { final AssetManager assetManager = getAssetManager(); for (final String id : bundles.keys()) { final String path = determinePath(id); try { assetManager.unload(path); } catch (final Exception exception) { Exceptions.ignore(exception); // Asset not loaded. Somewhat expected. } final I18NBundle bundle = I18NBundle.createBundle(Gdx.files.internal(path), locale, encoding); bundles.put(id, bundle); final EagerI18NBundleParameter parameters = new EagerI18NBundleParameter(bundle); assetManager.load(path, I18NBundle.class, parameters); assetManager.finishLoadingAsset(path); for (final BundleInjection injection : bundlesData.get(id)) { injection.inject(bundle); } parser.getData().addI18nBundle(id, bundle); if (defaultBundle.equals(id)) { parser.getData().setDefaultI18nBundle(bundle); } } } @Override protected String getFolder() { return "i18n"; } @Override protected String[] getExtensions() { return EXTENSIONS; } }